package ev;

import java.util.ArrayList;

import java.util.Collections;
import java.util.Random;

import TeamPursuit.MensTeamPursuit;
import TeamPursuit.SimulationResult;
import TeamPursuit.WomensTeamPursuit;
import ev.initial.Individual;
import ev.initial.InitialMenSetUp2;
import ev.operator.Crossover;
import ev.operator.Cycle;
import ev.operator.Mutation;
import ev.operator.Swap;
import ev.operator.bigSwap;
import ev.selection.Selection;
import ev.selection.SimpleSelection;

public class EA_Team_Men4 implements Team_Men{

	private ArrayList<Individual> p;
	private SimulationResult bestResult;
	private double bestTime;
	public EA_Team_Men4()
	{
		new InitialMenSetUp2();
		
		bestResult = null;
		bestTime = Double.MAX_VALUE;
        MensTeamPursuit mensTeamPursuit = new MensTeamPursuit();
        try {
			
			mensTeamPursuit.setHeight(0, 1.80);
			mensTeamPursuit.setWeight(0, 80.0);
			mensTeamPursuit.setMeanMaximumPower(0, 6.5);
			
			mensTeamPursuit.setHeight(2, 1.70);
			mensTeamPursuit.setWeight(2, 70.0);
			mensTeamPursuit.setMeanMaximumPower(2, 5.5);
			
			mensTeamPursuit.setHeight(3, 1.80);
			mensTeamPursuit.setWeight(3, 80.0);
			mensTeamPursuit.setMeanMaximumPower(3, 5.5);
			
			//result = mensTeamPursuit.simulate(DEFAULT_MENS_TRANSITION_STRATEGY, DEFAULT_MENS_PACING_STRATEGY);
		} catch (Exception e) {
			e.printStackTrace();
		}
		p = InitialMenSetUp2.data;
	}
	public void emulation() {
		SimulationResult result = null;
		MensTeamPursuit mensTeamPursuit = new MensTeamPursuit();
		//initial population whose size is three
		int times=2000;
		while(times>0)
		{
			times--;
			mutateStrategy(p);
			evolvePacing(p);
		}
	}
	//set the population strategy to the same after mutation
	private void mutateStrategy(ArrayList<Individual> p) {
		
		int count =10;
		Mutation m=new Swap();
		Individual d =p.get(0);
		boolean[] previousStrategy = d.getStrategy();
			previousStrategy =m.mutate(previousStrategy);			
		
		for(Individual i : p)
		{
			i.setStrategy(previousStrategy);
		}
	}

	private void evolvePacing(ArrayList<Individual> p) {
		Random r = new Random();
		SimulationResult result = null;
        MensTeamPursuit mensTeamPursuit = new MensTeamPursuit();
        Selection s=new SimpleSelection();
        int mutationRate = 3;
        int crossOverRate = 7;
        int count = 20000;
		Mutation mutate = new Swap();
		Mutation bigMutate = new bigSwap();
		Crossover cross =new Cycle();
		while (count > 0) {
			count--;
			int c = r.nextInt(10);			
			for (int i = 0; i < p.size(); i++) {
				Individual p3 = p.get(i);
				int m = r.nextInt(10);
				if (m < 2) {
					do {
						mutate.mutate(p3.getPacing());
						try {
							result = mensTeamPursuit.simulate(
									p3.getStrategy(), p3.getPacing());
							if(this.totalEnergyRemaining(result.getEnergyRemaining())>500)
							{
								bigMutate.mutate(p3.getPacing());
							}
						} catch (Exception e) {
							e.printStackTrace();
						}
					} while (!isValid(result));
					p3.setTime(result.getFinishTime());

				}			
			}
			
			if (c < 7) {
				Individual newIndiv = null;
				do{
					Individual p1 = p.get(r.nextInt(5)).copy();
					Individual p2 = p.get(r.nextInt(5)).copy();

					boolean[] a = cross.cross(p1.getStrategy(), p2.getStrategy());
					int[] b = cross.cross(p1.getPacing(), p2.getPacing());
					newIndiv = new Individual(a, b);

					try {
						result = mensTeamPursuit.simulate(a, b);
					} catch (Exception e) {
						e.printStackTrace();
					}

				}while(!isValid(result));
				newIndiv.setTime(result.getFinishTime());
				p.add(newIndiv);
				p = s.select(p, 5);
			}
			Collections.sort(p);
			double time = p.get(0).getTime();
			if(time<bestTime)
			{
				bestTime = time;
				System.out.println(bestTime);
			}
			
		}
	}
	


	private boolean isValid(SimulationResult result){
		if(result.getProportionCompleted() < 0.9999998){
			return false;
		}else{
			return true;
		}
	}
	private double totalEnergyRemaining(double[] EnergyRemaining){
		double total=0;
		for(int i=0;i<EnergyRemaining.length;i++){
			total=total+EnergyRemaining[i];
		}
		return total;
	}

}
